
(define lessons
  '(
    ;; lesson 0
    "Hello! I'm Professor Scott.

You must want me to help you learn Scheme.

So let's go to the first lesson. Say:

> (next-lesson! prof-scott)

"

    ;; lesson 1
    "Cool ! (I like to say Cooool :) ).
You've just executed a Scheme expression.
More precisely, you evaluated the procedure next-lesson! with the argument prof-scott (it's me !).

Note you can run this tutorial again by evaluating: 

> (repeat-lesson! prof-scott)

To return to the previous lesson, evaluate:
 
> (previous-lesson! prof-scott)

Try to evaluate this expression:

> (display \"hello world!\\n\")

Then go to the next lesson:

> (next-lesson! prof-scott)

"

    ;; lesson 2
    "You now know how to execute Scheme code. 

Now let's talk about basic data types.

1, 2, 100, 2/3 ... are numbers, and have many procedures that operate on them.
Evaluate these ones:

> 2

> 1/3

> (+ 1/3 4/5)

> (round 18/5)

> (- 1)

> (- (- 1))

> (odd? (+ 1 3))

When you are done, say:

> (next-lesson! prof-scott)

"

"A character is represented by a #\\ before the character itself.

> #\\A

> (char->integer #\\B)

> #\\return

> #\\space

> (next-lesson! prof-scott)

"

"A string is a collection of characters. Use double quotes to enclose a string. Print these expressions:

> \"prof-scott\"

> (string-length \"prof-scott\")

> (string-upcase \"abc\")

> (list->string (reverse (string->list \"Hello World\")))

You can access each character using the string-ref procedure.

> (string-ref \"prof-scott\" 0)

String concatenation uses the string-append procedure:

> (string-append \"prof-scott\" \" is cool\")

> (next-lesson! prof-scott)

"

"A symbol is a string which is guaranteed to be globally unique. 

There is one and only one symbol 'prof-scott. There may be several \"prof-scott\" strings.

eq? returns true only if the two arguments are the same.

> (string->symbol \"prof-scott\")

> (symbol->string 'prof-scott)

> (eq? (number->string 2) (number->string 2))

> (eq? (string->symbol (number->string 2)) (string->symbol (number->string 2)))

> (next-lesson! prof-scott)

"

"Literal lists can be created by quoting them:

> '(1 2 3)

> (length '(1 2 3 (4 5 6)))

> (null? '(1 2 4))

> (list-ref '(1 2 3) 0)

> (next-lesson! prof-scott)

"

"Lists can also be created dynamically using the list procedure:

> (list (+ 2 3) (* 6 6))

> (length (list (+ 2 3) (* 6 6) (string-append \"hello\" \" Scott\")))

> (next-lesson! (list-ref (list prof-scott) 0))

"

"Mathematical operations are just ordinary procedures in Scheme.

The operator comes before the arguments in the expression, not between them.

This means that order of operations is simply the arguments given to each procedure.

> (* (+ 2 2) 10)

> (+ 2 (* 2 10))

> (/ (- 8 5) 2)

> (- 8 (/ 5 2))

> (next-lesson! prof-scott)

"

"Math is cool! Let's talk about lambdas.

Lambdas are anonymous procedures that can be stored into variables and executed on demand.

Lambdas have a special syntax:

> (lambda () (display \"Hello\"))

does not display anything because the body of the lambda is not executed.

Here is a lambda that adds 2 to its argument (its argument is named x):

> (lambda (x) (+ x 2))

We can execute a lambda by using it like any other procedure:

> ((lambda (x) (+ x 2)) 5)

> ((lambda () (display \"Hello\")))

> ((lambda (x) (+ x 2)) 10)

> ((lambda (x y) (+ x y)) 3 5)

> ((lambda () (next-lesson! prof-scott)))

"

"Lambdas can be assigned to a variable then executed later.

> (define b (lambda (x) (+ x 2)))

> (b 12)

There is also a shorthand that means the same thing:

> (define (b2 x) (+ x 2))

> (b2 12)

> (next-lesson! prof-scott)

"

"Conditionals follow the form (if predicate? consequent alternative).

> (if (< 1 2) 100 42)

Conditionals without an alternative path, or with multi-line consequents, should use cond.

> (cond ((> 3 10) (display \"Maybe there\\\"s a bug...\")) (else (display \"No: 3 is less than 10\")))

> (cond ((= 3 3) (next-lesson! prof-scott)))

"

"In order to execute a loop, it is necessary to define a named lambda.

> (let p ((i 1)) (when (<= i 100) (display i) (newline) (p (+ i 1))))

> (let p ((i 1)) (when (<= i 100) (display i) (newline) (p (+ i 3))))

> (let p ((i 100)) (when (>= i 0) (display i) (newline) (p (- i 2))))

> (next-lesson! prof-scott)

"

"There are some higher-order procedures that take a procedure and a list as its arguments.

> (for-each (lambda (n) (display n) (newline)) '(11 38 3 -2 10))

> (map abs '(11 38 3 -2 10))

> (map odd? '(11 38 3 -2 10))

> (for-each next-lesson! (list prof-scott))

"

"This tutorial is done. Enjoy programming with Scheme.

See you soon!

"
    ))

(define prof-scott
  (let ((current-lesson -1))
    (define (display-lesson n)
      (define max-lesson (length lessons))
      (define as-string (string-append "("
                                       (number->string (+ 1 n))
                                       "/"
                                       (number->string max-lesson)
                                       ")"))
      (display as-string)
      (newline)
      (newline)
      (display (list-ref lessons n)))
    
    (lambda (msg self . rest)
      (case msg
        ((previous-lesson!)
         (cond
          ((<= current-lesson 0)
           (display "There are no previous lessons.\n"))
          (else
           (set! current-lesson (- current-lesson 1))
           (display-lesson current-lesson))))
        ((repeat-lesson!)
         (display-lesson current-lesson))
        ((next-lesson!)
         (cond
          ((>= current-lesson (- (length lessons) 1))
           (display "There are no further lessons.\n"))
          (else
           (set! current-lesson (+ 1 current-lesson))
           (display-lesson current-lesson))))))))

(define (next-lesson! obj)
  (obj 'next-lesson! obj))

(define (repeat-lesson! obj)
  (obj 'repeat-lesson! obj))

(define (previous-lesson! obj)
  (obj 'previous-lesson! obj))

(define (main)
  (next-lesson! prof-scott))

